home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
011
/
device2.arc
/
DEVICE.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1984-01-01
|
10KB
|
314 lines
program Print_Device_Driver_Chain(input,output);
{*********************************************************************
* DEVICE.PAS program for displaying device driver chain *
* for DOS 2.00,2.10,3.00,3.10 *
* *
* by Tim MacNary july 13,1985 *
* Turbo Pascal v. 2.00B PC-DOS *
* *
* Adapted from a Lattice C program by Stan Mitchell, published in *
* Dr. Dobb's Journal, #103 May, 1985, page 122. *
* Please keep this comment here. *
*********************************************************************
This routine uses fields of a standard FCB that Microsoft, in
it's wisdom, declined to make public. Contained in each opened FCB
are a Segment:Offset pair that point to the device drive used to
access the opened file: if you open a disk file, then the driver
interface to the disk drives is used; if the CON: device, then
the console driver is used.
DOS keeps track of the drivers by means of a linked list. Each
driver has a header area which defines what that device can do, it's
name, where it's entry points are, and the address of the next driver
in the list. There is one special driver in the list: the NUL: device.
It is always at the beginning of the list, so all other drivers will
follow it.
The routine is as follows:
begin
Determine what DOS version being used
Exit if the version = 0 ( means dos 1.xx )
Initial an FCB with the NUL: device name.
Open the file; exit if error.
Get the pointers from the FCB; the pointers are in different places
for DOS 2 and 3.
Set up the screen --make it look nice
Repeat
Output the header
Get the next header
Until the next header offset field = $FFFF
Output the last header
Finish the screen display
end
}
const
{ DOS Function codes }
OpenFCB = $0F00;
CloseFCB = $1000;
DOS_Version = $3000;
type
DevHdr = record
Next_Hdr_Offs,
Next_Hdr_Seg,
Attributes,
Strategy,
Interrupt:integer;
Dev_Name:array[1..8] of char;
end;
DevHdr_Ptr = ^DevHdr;
{ The next two record types are used to access the pointers in
the FCB }
Reserve_V2 = record
time: integer;
attribute : byte;
device_header_offset, device_header_segment: integer;
Unknown : array[1..3] of byte;
end;
Reserve_V3 = record
time: integer;
attribute : integer;
device_header_offset, device_header_segment: integer;
Unknown : array[1..2] of byte;
end;
NameType = array[1..11] of char;
FCB_Type = record
drive:byte;
fname:NameType;
current_block :integer;
record_size: integer;
file_size: array[1..2] of integer;
date: integer;
RSU: array[1..10] of byte; { This is where the device pointer is stored }
bset : array[1..5] of byte;
end;
var
device : DevHdr_Ptr;
file_control_block : FCB_Type;
rsv2_x: ^reserve_V2;
rsv3_x: ^reserve_V3;
Error:integer;
Hdr_Seg,Hdr_Offs:integer;
Version,Minor:integer;
procedure Init_FCB(Drive:byte;Name:NameType;var File_Control_Block:FCB_Type);
{ Fill in the Drive and File fields of the FCB.
Returns an initialized File Control Block. }
begin
File_Control_Block.Drive:=Drive;
File_Control_Block.FName:=Name;
end; { Init_FCB }
procedure Open_Device(var File_Control_Block:FCB_Type;var Error:integer);
{ The equivalent of either a reset or a rewrite in Turbo Pascal }
var Regs: record
AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:integer;
end;
begin
Regs.DS:=SEG(File_Control_Block);
Regs.DX:=OFS(File_Control_Block);
Regs.AX:=OpenFCB;
MSDOS(Regs);
Error:=LO(Regs.AX);
end;
procedure Hex_Output(Value:integer);
{ Convert value to a hex string and output it, right-justified in a
4 character field. }
var Rem:integer;
OutStr:string[4];
begin
OutStr:='';
repeat
Rem:=Value MOD 16; { Get remainder }
Value:=Value DIV 16; { calculate quotient }
{ Convert to A-F if necessary }
if Rem > 9 then OutStr:=CHR(Rem + ORD('A') - 10 ) + OutStr
else OutStr:=CHR(Rem + ORD('0')) + OutStr;
until Value = 0;
{ Justify the answer a la Turbo }
for Rem:=1 TO 4 - Length(OutStr) DO
write(' ');
write(OutStr);
end { Hex_Output };
procedure Print_Header(Dev:DevHdr_Ptr;Hdr_Seg,Hdr_Offs:integer);
{ Print a device driver header }
type Str4=string[4];
var Co,Co2:integer;
procedure WriteIfEqual(Attributes,Mask:integer;Str:Str4;var Co:integer);
{ If an attribute is present, then print out a 4 character attribute indicator. }
begin
if Attributes AND Mask <> 0 then
begin
write(Str);
Co:=Co + 1
end
end;
begin
Co:=0;
write('│ ');
Hex_Output(Hdr_Seg);
write(' │');
Hex_Output(Hdr_Offs);
write(' │ ');
WITH Dev^ DO
begin
if (Attributes AND $8000) = 0000 then { Block device }
begin
write('# Blocks:');
{ write out block number}
write(ORD(Dev_Name[1]):2);
write(' │ ');
end
else begin
WriteIfEqual(Attributes,$0001,'StI ',Co);
WriteIfEqual(Attributes,$0002,'StO ',Co);
WriteIfEqual(Attributes,$0004,'Nul ',Co);
WriteIfEqual(Attributes,$0008,'Clk ',Co);
WriteIfEqual(Attributes,$0010,'Spl ',Co);
WriteIfEqual(Attributes,$4000,'IOC ',Co);
for Co2 := 1 TO (3-Co) DO write(' ');
write('│ ');
for Co:=1 TO 8 DO write(Dev_Name[Co]); { Character device }
end;
write(' │');
Hex_Output(Strategy);
write(' │');
Hex_Output(Interrupt);
write(' │')
end;
writeln
end;
procedure Get_DOS_Version(var Major,Minor:integer);
{ Call MS-DOS to get the dos version number. The two returned values should
be displayed: write(Major:1,'.',Minor:2); Dos 1.xx will return a major
version number of 0. }
var Regs: record
AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:integer;
end;
begin
Regs.AX:=DOS_Version;
MSDOS(Regs);
Major:=LO(Regs.AX);
Minor:=HI(Regs.AX);
end;
procedure Set_Up_Screen(Version,Minor:integer);
{ Write out the column headers, etc }
begin
write( ' ');
TEXTCOLOR(BLACK);
TEXTBACKGROUND(WHITE);
writeln('╔═════════════════════╗');
TEXTCOLOR(WHITE);
TEXTBACKGROUND(BLACK);
write( ' ');
TEXTCOLOR(BLACK);
TEXTBACKGROUND(WHITE);
writeln('║ Device Driver Chain ║');
writeln('╒═════════════════════╩═════════════════════╩═══════════════════╕');
writeln('│ DOS Version ',Version:1,'.',Minor:2,' │');
writeln('├───────────────────────────────────────────────────────────────┤');
writeln('│ Segment Offset Attributes Name Strategy Interrupt │');
writeln('├─────────┬───────┬─────────────┬──────────┬─────────┬──────────┤');
end; { Set_Up_Screen }
procedure Finish_Screen;
begin
writeln('├─────────┴───────┴─────────────┴──────────┴─────────┴──────────┤');
writeln('│ StI=Standard Input StO=Standard Output Nul=Nul Device │');
writeln('│ Spl=Special Clk=Clock IOC=Input/Output Control │');
writeln('└───────────────────────────────────────────────────────────────┘');
end; { Finish_Screen }
begin
Get_DOS_Version(Version,Minor);
if Version = 0 then { DOS 1.xx used }
begin
writeln('MS-DOS 2.xx or 3.xx required; exiting ...');
repeat until KEYPRESSED;
HALT
end;
{ Get nul: header location by Opening it; the FCB has fields containing
the SEG:OFS of the NUL device. }
Init_FCB(0,'NUL ',File_Control_Block);
Open_Device(File_Control_Block,Error);
if Error = 0 then { Nul device opened successfully }
begin
case Version of { DOS 2.xx and 3.xx allocate the FCB differently }
2: { DOS 2.xx }
begin
rsv2_x:=PTR(SEG(File_Control_Block),
OFS(File_Control_Block)+22);
Device:=PTR(rsv2_x^.Device_Header_Segment,
rsv2_x^.Device_Header_Offset);
Hdr_Seg :=rsv2_x^.Device_Header_Segment;
Hdr_Offs:=rsv2_x^.Device_Header_Offset;
end;
3: { DOS 3.xx }
begin
rsv3_x:=PTR(SEG(File_Control_Block),
OFS(File_Control_Block)+22);
Device:=PTR(rsv3_x^.Device_Header_Segment,
rsv3_x^.Device_Header_Offset);
Hdr_Seg :=rsv3_x^.Device_Header_Segment;
Hdr_Offs:=rsv3_x^.Device_Header_Offset;
end;
else begin
writeln('DOS Version ',Version:2,'.',Minor:2,' not supported.');
halt;
end;
end; { case }
Set_Up_Screen(Version,Minor);
repeat { loop down the device chain }
Print_Header(Device,Hdr_Seg,Hdr_Offs);
{ Get next header location }
Hdr_Seg:= Device^.Next_Hdr_Seg;
Hdr_Offs:=Device^.Next_Hdr_Offs;
Device:=PTR(Device^.Next_Hdr_Seg,Device^.Next_Hdr_Offs);
until ( Device^.Next_Hdr_Offs = $FFFF ); { Until last Header }
Print_Header(Device,Hdr_Seg,Hdr_Offs);
Finish_Screen
end
else writeln('Error Opening Nul: device; error=',Error:1,'.');
repeat until KeyPressed;
end.